package fr.upmc.i3s.upmcontact.views.fragments;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TextView;
import fr.upmc.i3s.upmcontact.Constants;
import fr.upmc.i3s.upmcontact.R;
import fr.upmc.i3s.upmcontact.backend.BackEndBridgeImpl;
import fr.upmc.i3s.upmcontact.callbacks.IGetDataCallback;
import fr.upmc.i3s.upmcontact.callbacks.IPostDataCallback;
import fr.upmc.i3s.upmcontact.content.collectors.CollectorsController;
import fr.upmc.i3s.upmcontact.content.collectors.UpdateDatesManager;
import fr.upmc.i3s.upmcontact.content.containers.CollectedContentManager;
import fr.upmc.i3s.upmcontact.content.containers.IContainer;
import fr.upmc.i3s.upmcontact.contents.ChatMessage;
import fr.upmc.i3s.upmcontact.librairies.pulltorefresh.PullToRefreshBase;
import fr.upmc.i3s.upmcontact.librairies.pulltorefresh.PullToRefreshBase.OnRefreshListener;
import fr.upmc.i3s.upmcontact.librairies.pulltorefresh.PullToRefreshScrollView;
import fr.upmc.i3s.upmcontact.tools.DateUtils;
import fr.upmc.i3s.upmcontact.tools.FileUtils;
import fr.upmc.i3s.upmcontact.views.FragmentController;
import fr.upmc.i3s.upmcontact.views.fragments.models.IFragmentModel;
import fr.upmc.i3s.upmcontact.views.fragments.models.PageFragmentModel;

public class ChatFragment extends PageFragmentModel implements IFragmentModel {
	
	private static final String TAG = "ChatFragment";
	
	private FragmentController fragmentController;
	private static volatile ChatFragment INSTANCE;
	
	private PullToRefreshScrollView prsvContent;
	private TableLayout tlFeed;
	private EditText etMessage;
	private Button bSend;
	private TextView tvFeetLeft;
	private TextView tvFeetRight;
	private ImageView ivArrowLeft;
	private ImageView ivArrowRight;
	
	public static ChatFragment getInstance() {
		if(INSTANCE == null) {
			ChatFragment fragment = new ChatFragment();
		    Bundle bundle = new Bundle(3);
		    bundle.putInt(EXTRA_LAYOUT_FRAGMENT, R.layout.fragment_chat);
		    bundle.putInt(EXTRA_HEAD_ICON, R.drawable.ic_menu_chat_white);
		    bundle.putInt(EXTRA_HEAD_TEXT, R.string.title_fragment_chat);
		    fragment.setArguments(bundle);
		    INSTANCE = fragment;
		}
	    return INSTANCE;
	}
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		return super.onCreateView(inflater, container, savedInstanceState);
	}
	
 	@Override
	public void onViewCreated(View view, Bundle savedInstanceState) {
		super.initFragmentViews();
		this.fragmentController = (FragmentController) getActivity();
		fetchViews();
		customizeViews();
		setListeners();
	}
 	
 	@Override
 	public void fetchViews() {
 		this.prsvContent = (PullToRefreshScrollView) this.getView().findViewById(R.id.pullToRefreshScrollview_content);
 		this.tlFeed = (TableLayout) this.getView().findViewById(R.id.tableLayout_feed);
 		this.etMessage = (EditText) this.getView().findViewById(R.id.editText_message);
 		this.bSend = (Button) this.getView().findViewById(R.id.button_send);
 		this.tvFeetLeft = (TextView) this.getView().findViewById(R.id.textView_feet_text_left);
 		this.tvFeetRight = (TextView) this.getView().findViewById(R.id.textView_feet_text_right);
 		this.ivArrowLeft = (ImageView) this.getView().findViewById(R.id.imageView_feet_arrow_left);
 		this.ivArrowRight = (ImageView) this.getView().findViewById(R.id.imageView_feet_arrow_right);
 	}
 	
 	@Override
 	public void customizeViews() {
 		this.tvFeetLeft.setText("");
 		this.tvFeetRight.setText("");
 		this.ivArrowLeft.setVisibility(View.GONE);
 		this.ivArrowRight.setVisibility(View.GONE);
 		// set last update date for pull to refresh :
 		updateDate();
 		// fill table row feed with informations :
 		fillFeed();
 	}
 	
 	@Override
 	public void setListeners() {
 		this.prsvContent.setOnRefreshListener(onContentRefreshListener);
 		this.bSend.setOnClickListener(onSendClickListener);
 		this.etMessage.setOnTouchListener(onMessageTouchListener);
 	}
 	
	private void updateDate() {
 		this.prsvContent.getLoadingLayoutProxy().setLastUpdatedLabel(
 				fragmentController.getString(R.string.pull_to_refresh_last_update)+" "+
 				DateUtils.toDisplayDateTime(UpdateDatesManager.retrieveUpdateChatMessageDate(fragmentController)));
	}
 	
 	private void fillFeed() {
 		tlFeed.removeAllViews();
 		LayoutInflater inflater = (LayoutInflater) fragmentController.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 		for(ChatMessage cm : CollectedContentManager.getInstance(getActivity()).getChatMessages()) {
 			Log.i(TAG, "ChatMessage="+cm);
 			tlFeed.addView(createRowForInformation(inflater, cm));
 			tlFeed.addView(createSeparator(inflater));
 		}
 	}
 	
 	private View createRowForInformation(LayoutInflater inflater, ChatMessage cm) {
 		View row = inflater.inflate(R.layout.layout_row_chat_message, null);
 		// fetch views
 		TextView tvMessage = (TextView) row.findViewById(R.id.textView_message);
 		TextView tvDate = (TextView) row.findViewById(R.id.textView_date);
 		// custom views
 		tvMessage.setText(Html.fromHtml(
 				"<b>"+cm.getFrom().getUsername()+"</b> : "+
 				cm.getMessageContent()));
 		tvDate.setText(Html.fromHtml(
 				DateUtils.toDisplayDate(cm.getCreatedAt())+"<br>"+
 				DateUtils.toDisplayTime(cm.getCreatedAt())));
 		// change IDs
 		int randId = (int) Math.round(Math.random()*1000);
 		row.setId(row.getId()+randId);
 		tvMessage.setId(tvMessage.getId()+randId);
 		tvDate.setId(tvDate.getId()+randId);
 		return row;
 	}
 	
    private View createSeparator(LayoutInflater inflater) {
        View separator = inflater.inflate(R.layout.layout_separator, null);
        return separator;
    }
 	
 	
 	  ///////////////
 	 // CALLBACKS //
 	///////////////
 	
	private IGetDataCallback getChatMessagesCallback = new IGetDataCallback() {
		@Override
		public void getDataEndedOk(LinkedList<Object> list) {
			Log.i(TAG, "getChatMessagesCallback.getDataEndedOk.list.size="+list.size());
			CollectedContentManager.getInstance(fragmentController).getChatMessages().updateWith(list);
			UpdateDatesManager.storeChatMessagesUpdateDate(getActivity());
			// sort by ascending date
			CollectedContentManager.getInstance(fragmentController).getChatMessages().sortBy(IContainer.ASCENDING);
			// save content for offline access :
			CollectedContentManager.getInstance(fragmentController).getChatMessages().saveState(fragmentController);
			// delete unused local files :
			List<String> exceptedFiles = CollectedContentManager.getInstance(fragmentController).getChatMessages().getRequiredExternalFileList();
			FileUtils.rmAllFilesInDirectoryExcept(Constants.CHAT_MESSAGES_EXTERNAL_FOLDER, exceptedFiles);
	 		// re-use dialog in backendbridge
			BackEndBridgeImpl.getInstance(fragmentController).setCancelForAWhile(false);
			// set last update date for pull to refresh :
	 		updateDate();
			// feel feed view :
			fillFeed();
			prsvContent.onRefreshComplete();
		}
		@Override
		public void getDataEndedNok() {
			Log.w(TAG, "getChatMessagesCallback.getDataEndedNok");
			prsvContent.onRefreshComplete();
		}
	};
	
	
	private IPostDataCallback messagePostedCallback = new IPostDataCallback() {
		@Override
		public void posted(boolean success) {
			if(success) {
				// add the last generated chat message to its collected content
				ChatMessage cm = new ChatMessage(null, new Date(System.currentTimeMillis()), new Date(System.currentTimeMillis()), 
						etMessage.getEditableText().toString(),
						BackEndBridgeImpl.getInstance(fragmentController).getCurrentUser());
				CollectedContentManager.getInstance(fragmentController).getChatMessages().add(cm);
				// save content for offline access :
				CollectedContentManager.getInstance(fragmentController).getChatMessages().saveState(fragmentController);
		 		// re-use dialog in backendbridge
				BackEndBridgeImpl.getInstance(fragmentController).setCancelForAWhile(false);
				// display refreshed content :
				etMessage.setText("");
				fillFeed();
			}
		}
	};
	
	
	  ///////////////
	 // LISTENERS //
	///////////////
	
	private OnRefreshListener<ScrollView> onContentRefreshListener = new OnRefreshListener<ScrollView>() {
		@Override
		public void onRefresh(PullToRefreshBase<ScrollView> refreshView) {
			Log.i(TAG, "onContentRefreshListener.onRefresh");
			CollectorsController.getInstance(fragmentController)
			.getChatMessagesCollector()
			.collect(fragmentController, getChatMessagesCallback, true, true);
		}
	};
	
	private OnTouchListener onMessageTouchListener = new OnTouchListener() {
		@Override
		public boolean onTouch(View arg0, MotionEvent arg1) {
			etMessage.setText("");
			etMessage.setTextColor(Color.BLACK);
			return false;
		}
	};
	
	private OnClickListener onSendClickListener = new OnClickListener() {
		@Override
		public void onClick(View v) {
			String message = etMessage.getEditableText().toString();
			Log.i(TAG, "onSendClickListener.onClick.message="+message);
			if(message!=null && !message.equals("") && !message.equals(" ")) {
				// close keyboard :
				InputMethodManager imm = (InputMethodManager) fragmentController.getSystemService(Context.INPUT_METHOD_SERVICE);
				imm.hideSoftInputFromWindow(etMessage.getWindowToken(), 0);
				// send chat message to server
				ChatMessage cm = new ChatMessage(null, null, null, 
						message,
						BackEndBridgeImpl.getInstance(fragmentController).getCurrentUser());
				BackEndBridgeImpl.getInstance(fragmentController).postChatMessage(cm, messagePostedCallback);
			} else {
				etMessage.setText(R.string.error_invalid_message);
				etMessage.setTextColor(Color.RED);
			}
		}
	};
	
}
